package com.chujian.system.auth.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import com.chujian.client.wx.WxMaClient;
import com.chujian.framework.core.tsdata.Result;
import com.chujian.framework.enums.PlatId;
import com.chujian.framework.exception.BaseException;
import com.chujian.framework.exception.MsgException;
import com.chujian.framework.util.mybatis.MybatisUs;
import com.chujian.login.vo.LoginResult;
import com.chujian.login.vo.PcLoginInfo;
import com.chujian.sys.entity.SysUser;
import com.chujian.sys.entity.SysUserLogin;
import com.chujian.wx.entity.WxMinipUser;
import com.chujian.wx.vo.GetMaUserInfoVo;
import com.chujian.system.auth.service.ILoginService;
import com.chujian.system.auth.service.ITokenService;
import com.chujian.system.sys.service.IPasswordGen;
import com.chujian.system.sys.service.SysUserLoginService;
import com.chujian.system.sys.service.SysUserService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@AllArgsConstructor
@Component
@Slf4j
public class DefaultLoginService implements ILoginService {
    private final SysUserService userService;
    private final IPasswordGen passwordGen;
    private final ITokenService tokenService;
    private final WxMaClient maClient;
    private final SysUserLoginService userLoginService;

    @Override
    public LoginResult pcLogin(PcLoginInfo loginInfo) {
        SysUser sysUser;
        // 用户名登录
        if (PcLoginInfo.LOGIN_TYPE_USERNAME.equals(loginInfo.getLoginType())) {
            sysUser = this.loginByUsername(loginInfo);

        } else if (PcLoginInfo.LOGIN_TYPE_MOBILE.equals(loginInfo.getLoginType())) { // 手机号登录
            sysUser = this.loginByMobile(loginInfo);
        } else {
            throw new MsgException("无效登录方式");
        }
        // 生成token
        String token = genToken(loginInfo.getProdId(), PlatId.PC.getId(), sysUser);
        String refreshToken = genRefreshToken(loginInfo.getProdId(), PlatId.PC.getId(), sysUser);
        return new LoginResult()
                .setToken(token)
                .setRefreshToken(refreshToken);
    }

    @Override
    @Transactional
    public LoginResult loginMa(String appId, GetMaUserInfoVo getMaUserInfoVo) {
        Result<WxMinipUser> userInfoResult = maClient.getUserInfo(appId, getMaUserInfoVo);
        if (!userInfoResult.isSuccess()) {
            throw new MsgException("小程序登录失败");
        }

        // 生成登录信息
        SysUserLogin userLogin = userLoginService.saveSysUserLogin(userInfoResult.getData());
        return creLoginResult(getMaUserInfoVo.getProdId(), userLogin);
    }


    @Override
    public SysUser loginByUsername(PcLoginInfo loginInfo) {
        // TODO 验证码
        List<SysUser> list = userService.listByUserAccount(loginInfo.getUsername());
        if (CollUtil.isEmpty(list)) {
            throw new MsgException("用户名无效");
        }
        SysUser user = list.get(0);

        String pass = passwordGen.genPassword(loginInfo.getPassword(), user.getPasswordSalt());
        if (!pass.equals(user.getPassword())) {
            throw new MsgException("密码错误");
        }
        return user;
    }

    @Override
    public SysUser loginByMobile(PcLoginInfo loginInfo) {
        return null;
    }

    @Override
    public LoginResult tryGetMaToken(String appId, String openId, Long userLoginId, Long prodId, Long t) {
        // 5s内的请求，认为有效
        if (System.currentTimeMillis() / 1000 - t > 5) {
            throw new BaseException(1, "非法请求");
        }
        SysUserLogin userLogin = userLoginService.getById(userLoginId);
        if (userLogin == null) {
            throw new BaseException(2, "非法请求");
        }
        if (!openId.equals(userLogin.getWxMinipOpenId())) {
            throw new BaseException(3, "非法请求");
        }
        return creLoginResult(prodId, userLogin);
    }

    private LoginResult creLoginResult(Long prodId, SysUserLogin userLogin) {
        LoginResult loginResult = new LoginResult().setUserLogin(userLogin);

        // 已绑定用户
        if (0L != userLogin.getUserId()) {
            MybatisUs.execWithNoAc(ListUtil.toList("sys_user"), "获取token", () -> {

                SysUser sysUser = userService.getById(userLogin.getUserId());
                String token = genToken(prodId, PlatId.MA_POINT.getId(), sysUser);
                String refreshToken = genRefreshToken(prodId, PlatId.MA_POINT.getId(), sysUser);
                sysUser = userService.getSimpleUserInfo(sysUser);

                loginResult.setUser(sysUser);
                loginResult.setToken(token);
                loginResult.setRefreshToken(refreshToken);
            });
        }
        return loginResult;
    }

    private String genToken(Long prodId, Long platId, SysUser sysUser) {
        // 生成token
        String token;
        try {
            token = tokenService.genToken(prodId, platId, sysUser);
        } catch (Exception e) {
            log.error("token生成失败", e);
            throw new MsgException("token生成失败");
        }
        return token;
    }

    private String genRefreshToken(Long prodId, Long platId, SysUser sysUser) {
        // 生成token
        String token;
        try {
            token = tokenService.genRefreshToken(prodId, platId, sysUser);
        } catch (Exception e) {
            log.error("token生成失败", e);
            throw new MsgException("token生成失败");
        }
        return token;
    }


}
